﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Globalization;
using System.Windows.Forms;

namespace Useful.GUI
{
	public partial class IntervalDateTimePicker : UserControl
	{
		public enum DateTimeFormatType { FullDateTime, OnlyDate, OnlyTime }
        public enum PresetDefaultValues { Not, Today }

		public event EventHandler<EventArgs> ValuesChanged = delegate { };

		public IntervalDateTimePicker()
		{
			InitializeComponent();

		    DefaultDateTime = PresetDefaultValues.Today;
		}

		private void bPreset_Click(object sender, EventArgs e)
		{
			cmsPreset.Show(bPreset, bPreset.Width, 0);
		}

		public string Header
		{
			get
			{
				return gbMain.Text;
			}
			set
			{
				gbMain.Text = value;
			}
		}

		private DateTimeFormatType _DateTimeFormat = DateTimeFormatType.FullDateTime;
		public DateTimeFormatType DateTimeFormat
		{
			get
			{
				return _DateTimeFormat;
			}
			set
			{
				if (_DateTimeFormat != value)
				{
					_DateTimeFormat = value;

					SetDateTimeFormat(dtpBegin);
					SetDateTimeFormat(dtpEnd);
				}
			}
		}

		private void SetDateTimeFormat(DateTimePicker dtp)
		{
			Size oldSize = TextRenderer.MeasureText(dtp.CustomFormat, dtp.Font);

			switch (_DateTimeFormat)
			{
				case DateTimeFormatType.FullDateTime: dtp.CustomFormat = "dd.MM.yyyy HH:mm:ss"; break;
				case DateTimeFormatType.OnlyDate: dtp.CustomFormat = "dd.MM.yyyy"; break;
				case DateTimeFormatType.OnlyTime: dtp.CustomFormat = "HH:mm:ss"; break;
			}

			Size newSize = TextRenderer.MeasureText(dtp.CustomFormat, dtp.Font);

			dtp.Width += newSize.Width - oldSize.Width;

			if (_DateTimeFormat == DateTimeFormatType.OnlyDate)
				dtp.Width += 10;
		}

        private void SetDefaultDateTime(PresetDefaultValues preset)
        {
            DateTime now = DateTime.Now;
            DateTime today = now.Date;

            switch (preset)
            {
                case PresetDefaultValues.Today:
                    Begin = today;
                    End = now;
                    End = null;
                    break;
            }
        }

        [DefaultValue(PresetDefaultValues.Today)]
	    public PresetDefaultValues DefaultDateTime { get; set; }

	    private void IntervalDateTimePicker_Load(object sender, EventArgs e)
		{
			SetDateTimeFormat(dtpBegin);
			SetDateTimeFormat(dtpEnd);

			if (_UseDefaultPreset)
			{
				AddDefaultPreset();
			}

            SetDefaultDateTime(DefaultDateTime);
        }

		private DateTime GetDateTimeCore(DateTime dt)
		{
			switch (_DateTimeFormat)
			{
				case DateTimeFormatType.FullDateTime: return dt;
				case DateTimeFormatType.OnlyDate: return dt.Date;
				case DateTimeFormatType.OnlyTime: return dt.ToLocalTime();
				default: throw new ArgumentOutOfRangeException();
			}
		}

		private DateTime? GetDateTime(DateTimePicker dtp)
		{
			if (!_AllowNullValue && !dtp.Checked)
				throw new Exception("!_AllowNullValue && !dtp.Checked");

			return dtp.Checked ? (DateTime?)GetDateTimeCore(dtp.Value) : null;
		}

		private void SetDateTime(DateTimePicker dtp, DateTime? value, bool allowNull)
		{
			if (GetDateTime(dtp) != value)
			{
				if (value != null)
				{
					dtp.Checked = true;
					dtp.Value = GetDateTimeCore(value.Value);
				}
				else
				{
                    if (allowNull)
                        dtp.Checked = false;
                    else
                    {
                        MessageBoxHelper.ShowError("Запрещено устанавливать пустое значение");
                        //throw new Exception("!allowNull and value == null");
                    }
				}
			}
		}

		public DateTime? Begin
		{
			get
			{
				return GetDateTime(dtpBegin);
			}
			set
			{
				SetDateTime(dtpBegin, value, AllowBeginNullValue);
			}
		}

		public DateTime? End
		{
			get
			{
				return GetDateTime(dtpEnd);
			}
			set
			{
                SetDateTime(dtpEnd, value, AllowEndNullValue);
			}
		}

		public bool PresetVisible
		{
			get
			{
				return bPreset.Visible;
			}
			set
			{
				bPreset.Visible = value;
			}
		}

		private bool _AllowNullValue = true;
		public bool AllowNullValue
		{
			get
			{
				return _AllowNullValue;
			}
			set
			{
				if (_AllowNullValue != value)
				{
					_AllowNullValue = value;

					dtpBegin.ShowCheckBox = _AllowNullValue;
					dtpEnd.ShowCheckBox = _AllowNullValue;
				}
			}
		}

        private bool _AllowBeginNullValue = true;
        public bool AllowBeginNullValue
        {
            get
            {
                return _AllowBeginNullValue;
            }
            set
            {
                if (_AllowBeginNullValue != value)
                {
                    _AllowBeginNullValue = value && AllowNullValue;

                    dtpBegin.ShowCheckBox = _AllowBeginNullValue;
                }
            }
        }

        private bool _AllowEndNullValue = true;
        public bool AllowEndNullValue
        {
            get
            {
                return _AllowEndNullValue;
            }
            set
            {
                if (_AllowEndNullValue != value)
                {
                    _AllowEndNullValue = value && AllowNullValue;

                    dtpEnd.ShowCheckBox = _AllowEndNullValue;
                }
            }
        }

		public void ClearPreset()
		{
			cmsPreset.Items.Clear();
		}

		private static string GetMonthName(DateTime dt)
		{
			return CultureInfo.GetCultureInfo("RU-ru").DateTimeFormat.MonthNames[dt.Month - 1].ToLower();
		}

		private static string GetDayName(DateTime dt)
		{
			return CultureInfo.GetCultureInfo("RU-ru").DateTimeFormat.DayNames[(int)dt.DayOfWeek];
		}

		public DateTime GetDateByDayOfWeek(DateTime dt, DayOfWeek dof)
		{
			return DateTime.Now.AddDays(-(DateTime.Now.DayOfWeek - dof)).Date;
		}

		public void AddDefaultPreset()
		{
			DateTime now = DateTime.Now;
			DateTime today = now.Date;

            AddPreset("---", null, null);
            AddPreset("За последние 10 минут", now.AddMinutes(-10), now);

			AddPreset();

			AddPreset(String.Format("Сегодня ({0})", GetDayName(today)), today, now);
			AddPreset(String.Format("Вчера ({0})", GetDayName(today.AddDays(-1))), today.AddDays(-1), today);
			AddPreset(String.Format("Позавчера ({0})", GetDayName(today.AddDays(-2))), today.AddDays(-2), today.AddDays(-1));

			AddPreset();

			AddPreset("С понедельника до сейчас", GetDateByDayOfWeek(today, DayOfWeek.Monday), now);
			AddPreset("С понедельника до сегодня", GetDateByDayOfWeek(today, DayOfWeek.Monday), today);

			DateTime df = GetDateByDayOfWeek(today, DayOfWeek.Friday);
			if (df >= today)
				df = df.AddDays(-7);

			AddPreset("С пятницы до сегодня", df, today);

			DateTime dm = GetDateByDayOfWeek(today, DayOfWeek.Monday);
			AddPreset("За субботу и воскресенье", dm.AddDays(-2), dm);

			AddPreset();

			DateTime month = new DateTime(today.Year, today.Month, 1);

			AddPreset(String.Format("Текущий месяц ({0})", GetMonthName(month)), month, now);
			AddPreset(String.Format("Прошлый месяц ({0})", GetMonthName(month.AddMonths(-1))), month.AddMonths(-1), month);
			AddPreset(String.Format("Позапрошлый месяц ({0})", GetMonthName(month.AddMonths(-2))), month.AddMonths(-2), month.AddMonths(-1));
		}

		public void AddPreset(string header, DateTime? begin, DateTime? end)
		{
			ToolStripMenuItem item = new ToolStripMenuItem(header);
			item.Tag = new KeyValuePair<DateTime?, DateTime?>(begin, end);
			item.Click += item_Click;
			item.ToolTipText = String.Format("'{0:G}' - '{1:G}'", begin, end);

			cmsPreset.Items.Add(item);
		}

		public void AddPreset()
		{
			ToolStripSeparator item = new ToolStripSeparator();

			cmsPreset.Items.Add(item);
		}

		private void item_Click(object sender, EventArgs e)
		{
			ToolStripMenuItem item = (ToolStripMenuItem)sender;

			KeyValuePair<DateTime?, DateTime?> tag = (KeyValuePair<DateTime?, DateTime?>)item.Tag;

			Begin = tag.Key;
			End = tag.Value;

            ValuesChanged(this, EventArgs.Empty);
		}

		private bool _UseDefaultPreset = true;
		public bool UseDefaultPreset
		{
			get
			{
				return _UseDefaultPreset;
			}
			set
			{
				if (_UseDefaultPreset != value)
				{
					_UseDefaultPreset = value;

					ClearPreset();
					AddDefaultPreset();
				}
			}
		}

		private void dtpBegin_ValueChanged(object sender, EventArgs e)
		{
			ValuesChanged(this, EventArgs.Empty);
		}
	}
}
